home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d889.lha / SCSIUtil / SCSIutil.c < prev    next >
C/C++ Source or Header  |  1993-07-16  |  66KB  |  2,503 lines

  1. /*
  2.  *****    SCSIutil
  3.  *
  4.  *    A utility to do some low-level operations to a SCSI disk, e.g.
  5.  *
  6.  *        - start/stop motor
  7.  *        - read sectors
  8.  *        - read disk capacity info
  9.  *        - get inquiry info (manufacturers name etc)
  10.  *        - seek to a sector's cylinder (use to park heads)
  11.  *        - play audio tracks of a CD-DA
  12.  *        - eject/insert a medium
  13.  *        - read digital data off audio CDs (Sony 8003 = Apple CD300)
  14.  *
  15.  *    NOTE:  this program is based on SCSI information taken from
  16.  *           the accompanying documentation of a NEC D3841 SCSI disk.
  17.  *           I don't know the extent to which SCSI standards are
  18.  *           supported by that disk.
  19.  *
  20.  *           These commands work on the above disk. But a seek to
  21.  *           sector -1 (park on the NEC disk) fails on my Quantum 105.D
  22.  *
  23.  *    Program returns:
  24.  *    1 - init didn't work (maybe allocmem failed, etc.)
  25.  *    2 - wrong parameter count
  26.  *    3 - wrong parameter
  27.  *
  28.  *****    Written by Gary Duncan
  29.  *
  30.  *    Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
  31.  *
  32.  *    Gary Duncan
  33.  *    Philips PTS
  34.  *      23 Lakeside Dr
  35.  *    Tally-Ho Technology Park
  36.  *    Burwood East Vic 3151
  37.  *    Australia
  38.  *
  39.  * New features and rewrites by:
  40.  *
  41.  *    The Software Brewery
  42.  *    Heiko Rath
  43.  *    Raiffeisenstr.10a
  44.  *    D-6108 Weiterstadt
  45.  *    Germany
  46.  *
  47.  *    EMail: hr@brewhr.swb.de
  48.  *
  49.  *****    Freely distributable for non-commercial purposes
  50.  *
  51.  *    Compiles under Lattice 6.2
  52.  *    - needs AmigaDos 2.0  #includes
  53.  *
  54.  ***** Thanks to Markus Illenseer for some beta-testing.
  55.  *
  56.  *****    Function List :-
  57.  *
  58.  *    breakcheck()    by GD, modified by <HR>
  59.  *    __chkabort()    by <HR>
  60.  *    DoScsiCmd ()    by <HR>
  61.  *    err_str()    by GD
  62.  *    gcomp()        by GD
  63.  *    GetDevName()    by GD
  64.  *    id2string ()    by <HR>
  65.  *    init ()        by GD, modified by <HR>
  66.  *    inquiry()    by GD, modified by <HR>
  67.  *    mode_sense()    by <HR>
  68.  *    motor ()    by GD, modified by <HR>
  69.  *    play_audio ()    by <HR>
  70.  *    rawahexasciioutput()    by <HR>
  71.  *    rawhexoutput()    by <HR>
  72.  *    read_capacity()    by GD, modified by <HR>
  73.  *    read_cdblockheader()    by <HR>
  74.  *    read_cdda ()    by <HR>
  75.  *    read_cddaasync()    by <HR>
  76.  *    read_sec ()    by GD, modified by <HR>
  77.  *    read_sec_scsi ()    by GD, modified by <HR>
  78.  *    read_subchannel()    by <HR>
  79.  *    read_toc ()    by <HR>
  80.  *    seek ()        by GD, modified by <HR>
  81.  *    SendScsiCmd()    by <HR>
  82.  *    sense_errs()    by GD
  83.  *    usage()        by GD, modified by <HR>
  84.  *    WaitScsiCmd()    by <HR>
  85.  *
  86.  */
  87.  
  88. #define VERSION "1.815beta"
  89. /* #define HRTEST */        /* internal test version */
  90. #define ASYNC
  91.  
  92. /*
  93.  **** Includes
  94.  */
  95. #include <stdio.h>
  96. #include <string.h>
  97. #include <ctype.h>
  98. #include <exec/types.h>
  99. #include <exec/io.h>
  100. #include <exec/execbase.h>
  101. #include <exec/nodes.h>
  102. #include <exec/memory.h>
  103. #include <devices/trackdisk.h>
  104. #include <devices/scsidisk.h>
  105. #include <libraries/dos.h>
  106. #ifdef __SASC
  107. #include <proto/all.h>
  108. #endif
  109. #include "scsi_priv.h"
  110.  
  111. /*
  112.  **** Global variables
  113.  */
  114. UBYTE *ip_buf = NULL;
  115. UBYTE *scsi_data = NULL;
  116. UBYTE *toc_buf = NULL;
  117.  
  118. UBYTE *dev = "";
  119.  
  120. int scsi_id = -1;        /* ID of the SCSI device to send commands to */
  121. UBYTE *pname;
  122. UBYTE buffer[LINE_BUF];
  123. int secno = -1;
  124.  
  125. UBYTE *cdda_buf[NDBLBUF];
  126. MSGPORT *mp_ptr[NDBLBUF];
  127. IOSTDREQ *io_ptr[NDBLBUF];
  128. SCSICMD scsi_cmd[NDBLBUF];
  129. UBYTE *scsi_sense[NDBLBUF];
  130. UBYTE scsi_status[NDBLBUF];
  131. BYTE *mono_buf[NDBLBUF];
  132.  
  133. #ifdef HRTEST
  134. unsigned int subcode;
  135. #endif
  136.  
  137. #ifdef USE8SVX
  138. BYTE write8svx = FALSE;        /* convert to 8SVX */
  139. #endif    /* USE8SVX */
  140.  
  141. /*
  142.  **** Function descr.
  143.  */
  144. int breakcheck (void);
  145. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  146. UBYTE *err_str (int err);
  147. void exit (int status);
  148. int gcomp (char *p1, char *p2, int len);
  149. UBYTE *GetDevName (char *grep);
  150. UBYTE *id2string (int id, IDTOSTRING * idtable);
  151. BOOLEAN init (void);
  152. void inquiry (BOOLEAN parsedoutput);
  153. void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
  154. void motor (int motorstatus);
  155. void play_audio (int starttrack, int startindex, int endtrack, int endindex);
  156. void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
  157. void rawhexoutput (UBYTE *p, UWORD numbytes);
  158. void read_capacity (BOOLEAN parsed);
  159. void read_cdblockheader (BOOLEAN parsed, ULONG block);
  160. #ifndef ASYNC
  161. void read_cdda (ULONG startblock, ULONG numblocks, BYTE whichchannel, BYTE use16bit);
  162. #endif
  163. void read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel, BYTE use16bit);
  164. void read_sec (void);
  165. void read_sec_scsi (void);
  166. void read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track);
  167. void read_toc (int toclong);
  168. void seek (void);
  169. UBYTE *sense_errs (int req, int err);
  170. void usage (void);
  171.  
  172. int WaitScsiCmd (int req);
  173. void SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  174.  
  175. #ifdef __SASC
  176. void __regargs __chkabort (void);
  177. #endif    /* __SASC */
  178.  
  179.  
  180. /*********************************************************************
  181.  *
  182.  *    main
  183.  *
  184.  *
  185.  */
  186.  
  187. int
  188. main (int argc, char **argv)
  189. {
  190.   UBYTE *p;
  191.   int j = 0, i = 0;
  192.   int returnvalue = 0;
  193.  
  194.   if (argc == 1)
  195.     {
  196.       usage ();
  197.       exit (1);
  198.     }
  199.  
  200.   /*
  201.    *      see if a SCSI.device specified
  202.    */
  203.   if (strncmp (argv[1], "-d", 2) == 0)
  204.     {
  205.       j = 1;
  206.       dev = argv[1] + 2;
  207.     }
  208.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  209.     {
  210.       fprintf (stderr, "Error : no *scsi*.device in device list\n");
  211.       exit (1);
  212.     }
  213.   pname = argv[0];
  214.   if (argc < (j + 2))
  215.     {
  216.       usage ();            /* help inquiry */
  217.       exit (1);
  218.     }
  219.  
  220.   if (argc < (j + 3))
  221.     {
  222.       fprintf (stderr, "Error : Not enough params\n");
  223.       exit (1);
  224.     }
  225.   if (*(p = argv[j + 2]) != '-')
  226.     {
  227.       fprintf (stderr, "Error : bad option\n");
  228.       exit (1);
  229.     }
  230.  
  231.   /*
  232.    *    pick up SCSI id ; do a rough check
  233.    */
  234.   if (sscanf (argv[j + 1], "%d", &scsi_id) != 1 || scsi_id < 0)
  235.     {
  236.       fprintf (stderr, "Error : Bad scsi id\n");
  237.       exit (1);
  238.     }
  239.  
  240.   /*
  241.    *    now set up structures etc for SCSI xfer
  242.    */
  243.   if (init () == FALSE)
  244.     {
  245.       returnvalue = 1;
  246.       goto error;
  247.     }
  248.  
  249.   /*
  250.    **********************    now examine the options
  251.    */
  252.   if (argc == (j + 3))
  253.     /* commands without parameter */
  254.     {
  255.       switch (*++p)
  256.     {
  257.       /*
  258.            ****     read capacity
  259.            */
  260.     case 'c':
  261.       if (*++p == 'r')
  262.         {
  263.               read_capacity (FALSE);    /* output raw data */
  264.             }
  265.           else
  266.             {
  267.               read_capacity (TRUE);    /* output parsed data */
  268.             }
  269.       break;
  270.  
  271.       /*
  272.            ****     inquiry (raw)
  273.            */
  274.     case 'i':
  275.       if (*++p == 'r')
  276.         {
  277.               inquiry (FALSE);        /* output raw data */
  278.             }
  279.           else
  280.             {
  281.               inquiry (TRUE);        /* output parsed data */
  282.             }
  283.       break;
  284.  
  285.       /*
  286.            ****     read TOC
  287.            */
  288.     case 't':
  289.       if (*(p+1) == 'r')
  290.         {
  291.           read_toc(0);    /* output raw data */
  292.         }
  293.       else if (*(p+1) == 'l')
  294.         {
  295.           read_toc(2);    /* output long form */
  296.         }
  297.       else
  298.         {
  299.               read_toc(1);    /* output short form */
  300.         }
  301.       break;
  302.  
  303.     default:
  304.       fprintf (stderr, "Error : bad option\n");
  305.       returnvalue = 3;
  306.     }
  307.     }
  308.   else if (argc == (j + 4))
  309.     /* commands with one parameter */
  310.     {
  311.       switch (*++p)
  312.     {
  313.       /*
  314.            ****     change medium
  315.            */
  316.     case 'e':
  317.       {
  318.         int eject = -1;
  319.             
  320.             if (sscanf (argv[j + 3], "%d", &eject) != 1
  321.                 || ((eject != 0) && (eject != 1)))
  322.               {
  323.                 fprintf (stderr, "Error : eject/load control must be 0 or 1\n");
  324.                 returnvalue = 3;
  325.               }
  326.             else
  327.               {
  328.                 motor ((eject | 2));    /* eject/insert */
  329.               }
  330.       }
  331.       break;
  332.  
  333.       /*
  334.            ****     read CD-ROM data block address header
  335.            */
  336.     case 'h':
  337.       {
  338.         ULONG block;
  339.  
  340.         if (sscanf (argv[j + 3], "%lu", &block) != 1)
  341.           {
  342.             fprintf (stderr, "Error : Bad block no\n");
  343.             returnvalue = 3;
  344.           }
  345.         else
  346.           {
  347.             if (*++p == 'r')
  348.               {
  349.                 read_cdblockheader (FALSE, block);
  350.               }
  351.             else
  352.               {
  353.                 read_cdblockheader (TRUE, block);
  354.               }
  355.           }
  356.       }
  357.       break;
  358.  
  359.       /*
  360.            ****     stop/start motor
  361.            */
  362.     case 'm':
  363.       {
  364.         int motoronoff = -1;
  365.  
  366.             if (sscanf (argv[j + 3], "%d", &motoronoff) != 1
  367.                || ((motoronoff != 0) && (motoronoff != 1)) )
  368.               {
  369.                 fprintf (stderr, "Error : motor control must be 0 or 1\n");
  370.                 returnvalue = 3;
  371.               }
  372.             else
  373.               {
  374.                 motor (motoronoff);    /* turn on/off motor */
  375.               }
  376.       }
  377.       break;
  378.  
  379.       /*
  380.            ****     read sectors
  381.            */
  382.  
  383.     case 'r':
  384.       /*
  385.            *        get sector #
  386.            */
  387.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  388.         {
  389.           fprintf (stderr, "Error : Bad sec no\n");
  390.           returnvalue = 3;
  391.         }
  392.       else
  393.         {
  394.           if (*++p == 't')
  395.             {
  396.                   read_sec ();    /* read sector with trackdisk.device */
  397.             }
  398.           else
  399.             {
  400.                   read_sec_scsi ();    /* read sector with scsi */
  401.             }
  402.         }
  403.       break;
  404.  
  405.       /*
  406.            ****     seek to cylinder containing secno
  407.            */
  408.     case 's':
  409.       /*
  410.            *        get sector #
  411.            */
  412.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  413.         {
  414.           fprintf (stderr, "Error : Bad sec no\n");
  415.           returnvalue = 3;
  416.         }
  417.       else
  418.         {
  419.           seek ();
  420.         }
  421.       break;
  422.  
  423.     default:
  424.       fprintf (stderr, "Error : bad option\n");
  425.       returnvalue = 3;
  426.     }
  427.     }
  428.   else if (argc == (j + 5))
  429.     /* commands with two parameters */
  430.     {
  431.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  432.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  433.  
  434.       switch (*++p)
  435.     {
  436.       /*
  437.            ****     read CD-DA (16 bit raw left|right|stereo)
  438.            */
  439.     case 'd':
  440.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  441.         {
  442.           fprintf (stderr, "Error : must be -d{L|R|S}\n");
  443.           returnvalue = 3;
  444.         }
  445.       else
  446.         {
  447.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  448.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  449.             {
  450.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  451.               returnvalue = 3;
  452.             }
  453.           else
  454.             {
  455.                   read_cddaasync (startblock, numblocks, whichchannel, TRUE);
  456.             }
  457.         }
  458.       break;
  459.  
  460.       /*
  461.            ****     read CD-DA (8 bit left|right mono)
  462.            */
  463.     case 'D':
  464.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R')
  465.         {
  466.           fprintf (stderr, "Error : must be either -DL or -DR\n");
  467.           returnvalue = 3;
  468.         }
  469.       else
  470.         {
  471.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  472.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  473.             {
  474.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  475.               returnvalue = 3;
  476.             }
  477.           else
  478.             {
  479.                   read_cddaasync (startblock, numblocks, whichchannel, FALSE);
  480.             }
  481.         }
  482.       break;
  483.  
  484. #ifdef USE8SVX
  485.       /*
  486.            ****     read CD-DA (output 8SVX 8 bit left|right|stereo)
  487.            */
  488.     case '8':
  489.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  490.         {
  491.           fprintf (stderr, "Error : must be -8{L|R|S}\n");
  492.           returnvalue = 3;
  493.         }
  494.       else
  495.         {
  496.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  497.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  498.             {
  499.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  500.             }
  501.           else
  502.             {
  503.                   write8svx = TRUE;
  504.                   read_cddaasync (startblock, numblocks, whichchannel, FALSE);
  505.             }
  506.         }
  507.       break;
  508. #endif    /* USE8SVX */
  509.  
  510.       /*
  511.            ****     mode sense
  512.            */
  513.     case 'o':
  514.       {
  515.         int control, page;
  516.  
  517.             if (sscanf (argv[j + 3], "%d", &control) != 1 || control < 0 || control > 3)
  518.               {
  519.                 fprintf(stderr, "Error : invalid parameter for control (must be 0-4)\n");
  520.                 returnvalue = 3;
  521.               }
  522.             else
  523.               {
  524.                 if (sscanf (argv[j + 4], "%d", &page) != 1 || page < 0 || page > 0x3f)
  525.                   {
  526.                     fprintf(stderr, "Error : invalid parameter for page (must be 0-0x3f)\n");
  527.                     returnvalue = 3;
  528.                   }
  529.                 else
  530.                   {
  531.                     if (*++p == 'r')
  532.                       /* raw */
  533.                       {
  534.                         mode_sense (FALSE, control, page);
  535.                       }
  536.                     else
  537.                       /* parsed */
  538.                       {
  539.                         mode_sense (TRUE, control, page);
  540.                       }
  541.                   }
  542.               }
  543.       }
  544.           break;
  545.  
  546.  
  547.     default:
  548.       fprintf (stderr, "Error : bad option\n");
  549.       returnvalue = 3;
  550.     }
  551.     }
  552.   else if (argc == (j + 6))
  553.     /* commands with 3 parameters */
  554.     {
  555.       switch (*++p)
  556.         {
  557.  
  558.       /*
  559.            ****     read sub-channel information
  560.            */
  561.     case 'u':    /* raw */
  562.     case 'U':    /* parsed */
  563.       {
  564.         int trackno, subchannelformat, subchannel;
  565.  
  566.             /*
  567.              *        get sub-channel #
  568.              */
  569.             if (sscanf (argv[j + 3], "%d", &subchannel) != 1
  570.                 || subchannel < 0 || subchannel >255)
  571.               {
  572.                 fprintf (stderr, "Error : Sub-channel must be 0-255\n");
  573.                 returnvalue = 3;
  574.               }
  575.             /*
  576.              *        get sub-channel data format #
  577.              */
  578.             if (sscanf (argv[j + 4], "%d", &subchannelformat) != 1
  579.                 || subchannelformat < 0 || subchannelformat >255)
  580.               {
  581.                 fprintf (stderr, "Error : Sub-channel data format must be 0-255\n");
  582.                 returnvalue = 3;
  583.               }
  584.             /*
  585.              *        get track #
  586.              */
  587.             if (sscanf (argv[j + 5], "%d", &trackno) != 1 || trackno < 0
  588.                 || trackno > 99)
  589.               {
  590.                 fprintf (stderr, "Error : Bad track no (must be 1-99)\n");
  591.                 returnvalue = 3;
  592.               }
  593.             else
  594.               {
  595.                 if (*++p == 'r')
  596.                   {
  597.                     read_subchannel (FALSE,subchannel, subchannelformat, trackno);
  598.                   }
  599.                 else
  600.                   {
  601.                     read_subchannel (TRUE,subchannel, subchannelformat, trackno);
  602.                   }
  603.               }
  604.         }
  605.       break;
  606.  
  607. #ifdef HRTEST
  608.       /*
  609.            ****     read CD-DA (16 bit raw left|right|stereo)
  610.            */
  611.     case 'x':
  612.       {
  613.             ULONG startblock, numblocks;      /* used by the CDDA commands */
  614.             BYTE whichchannel = -1;           /* read left / right channel / stereo */
  615.  
  616.             if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  617.               {
  618.                 fprintf (stderr, "Error : must be -x{L|R|S}\n");
  619.                 returnvalue = 3;
  620.               }
  621.             else
  622.               {
  623.                 if (sscanf (argv[j + 3], "%u", &subcode) != 1
  624.             || sscanf (argv[j + 4], "%lu", &startblock) != 1
  625.                     || sscanf (argv[j + 5], "%lu", &numblocks) != 1)
  626.                   {
  627.                     returnvalue = 3;
  628.                   }
  629.                 else
  630.                   {
  631.                     read_cddaasync (startblock, 1, whichchannel, TRUE);
  632.                   }
  633.               }
  634.         }
  635.       break;
  636. #endif
  637.  
  638.     default:
  639.       fprintf (stderr, "Error : bad option\n");
  640.       returnvalue = 3;
  641.     }
  642.  
  643.     }
  644.  
  645.   else if (argc == (j + 7))
  646.     /* commands with 4 parameters */
  647.     {
  648.       switch (*++p)
  649.     {
  650.       /*
  651.            ****     play audio
  652.            */
  653.     case 'p':
  654.       {
  655.         int starttrack, startindex, endtrack, endindex;
  656.  
  657.             if (sscanf (argv[j + 3], "%d", &starttrack) != 1
  658.                 || (starttrack < 1) || (starttrack > 99))
  659.               {
  660.                 fprintf (stderr, "Error : Starting audio track must be in the range 1-99\n");
  661.                 returnvalue = 3;
  662.                 goto error;
  663.               }
  664.             if (sscanf (argv[j + 4], "%d", &startindex) != 1
  665.                 || (startindex < 0) || (startindex > 99))
  666.               {
  667.                 fprintf (stderr, "Error : Starting audio track index must be in the range 1-99\n");
  668.                 returnvalue = 3;
  669.                 goto error;
  670.               }
  671.             if (sscanf (argv[j + 5], "%d", &endtrack) != 1
  672.                 || (endtrack < 1) || (endtrack > 99))
  673.               {
  674.                 fprintf (stderr, "Error : Ending audio track must be in the range 1-99\n");
  675.                 returnvalue = 3;
  676.                 goto error;
  677.               }
  678.             if (sscanf (argv[j + 6], "%d", &endindex) != 1
  679.                 || (endindex < 0) || (endindex > 99))
  680.               {
  681.                 fprintf (stderr, "Error : Ending audio track index must be in the range 1-99\n");
  682.                 returnvalue = 3;
  683.                 goto error;
  684.               }
  685.             play_audio (starttrack, startindex, endtrack, endindex);
  686.       }
  687.       break;
  688.  
  689.     default:
  690.       fprintf (stderr, "Error : bad option\n");
  691.       returnvalue = 3;
  692.     }
  693.     }
  694.   else
  695.     {
  696.       fprintf (stderr, "Error : bad option\n");
  697.       returnvalue = 3;
  698.     }
  699.  
  700. error:
  701.  
  702.   for (i = 0; i < NDBLBUF; i++)
  703.     {
  704.       if (io_ptr[i])
  705.     {
  706.       CloseDevice ((struct IORequest *) io_ptr[i]);
  707.       DeleteStdIO (io_ptr[i]);
  708.     }
  709.  
  710.       if (cdda_buf[i])
  711.     FreeMem (cdda_buf[i], MAX_CDDALEN);
  712.  
  713.       if (mp_ptr[i])
  714.     DeletePort (mp_ptr[i]);
  715.  
  716.       if (scsi_sense[i])
  717.     FreeMem (scsi_sense[i], SENSE_LEN);
  718.  
  719.       if (mono_buf)
  720.     FreeMem (mono_buf[i], MAX_CDDALEN / 2);
  721.     }
  722.  
  723.   if (toc_buf)
  724.     FreeMem (toc_buf, MAX_TOC_LEN);
  725.  
  726.   if (ip_buf)
  727.     FreeMem (ip_buf, TD_SECTOR);
  728.  
  729.   if (scsi_data)
  730.     FreeMem (scsi_data, MAX_DATA_LEN);
  731.  
  732.   exit (returnvalue);
  733. }
  734.  
  735. /*********************************************************************
  736.  *
  737.  *    Initialization function
  738.  *
  739.  */
  740. BOOLEAN
  741. init (void)
  742. {
  743.   int i;
  744.  
  745.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  746.     {
  747.       fprintf (stderr, "AllocMem(0) Fail\n");
  748.       return FALSE;
  749.     }
  750.  
  751.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  752.     {
  753.       fprintf (stderr, "AllocMem(2) Fail\n");
  754.       return FALSE;
  755.     }
  756.  
  757.   if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
  758.     {
  759.       fprintf (stderr, "AllocMem(3) Fail\n");
  760.       return FALSE;
  761.     }
  762.  
  763.   for (i = 0; i < NDBLBUF; i++)
  764.     {
  765.       if ((scsi_sense[i] = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  766.     {
  767.       fprintf (stderr, "AllocMem (scsi_sense[%d]) Fail\n",i);
  768.       return FALSE;
  769.     }
  770.       if ((cdda_buf[i] = (UBYTE *) AllocMem (MAX_CDDALEN, 0)) == NULL)
  771.     {
  772.       fprintf (stderr, "AllocMem (cdda_buf[%d]) Fail\n",i);
  773.       return FALSE;
  774.     }
  775.  
  776.       if ((mp_ptr[i] = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  777.     {
  778.       fprintf (stderr, "CreatePort (mp_ptr[%d]) Fail\n",i);
  779.       return FALSE;
  780.     }
  781.       if ((io_ptr[i] = (IOSTDREQ *) CreateStdIO (mp_ptr[i])) == NULL)
  782.     {
  783.       fprintf (stderr, "CreateStdIO (io_ptr[%d]) Fail\n",i);
  784.       return FALSE;
  785.     }
  786.       if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr[i], 0) != 0)
  787.     {
  788.       fprintf (stderr,
  789.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  790.            io_ptr[i]->io_Error, dev, scsi_id, i);
  791.       return FALSE;
  792.     }
  793.       if ((mono_buf[i] = (BYTE *) AllocMem (MAX_CDDALEN / 2, 0)) == NULL)
  794.     {
  795.       fprintf (stderr, "AllocMem (mono_buf[%d]) Fail\n",i);
  796.       return FALSE;
  797.     }
  798.  
  799.     }
  800.  
  801.   return TRUE;
  802. }
  803.  
  804. /*********************************************************************
  805.  *
  806.  *    function to read parameter pages from a device
  807.  */
  808.  
  809. void
  810. mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page)
  811. {
  812.   static SCSICMD6 command =
  813.   {
  814.     SCSI_CMD_MSE,    /* 0x1a MODE SENSE scsi command */
  815.     PAD,        /* LUN | rsrvd. | DBD | rsrvd. */
  816.     0,            /* PC | Page Code */
  817.     PAD,        /* rsrvd. */
  818.     0,            /* allocation length */
  819.     PAD            /* control */
  820.   };
  821.  
  822.   static IDTOSTRING pagecontrolfield[] =
  823.   {
  824.     0x00, "Current Values",
  825.     0x01, "Changeable Values",
  826.     0x02, "Default Values",
  827.     0x03, "Saved Values",
  828.     -1, "Illegal value"
  829.   };
  830.  
  831.   UWORD i,j;
  832.   int err;
  833.  
  834.   command.b2 = (control<<6) | page;
  835.   command.b4 = MAX_DATA_LEN;
  836.  
  837.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  838.                         (UBYTE *) &command, sizeof (command),
  839.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  840.     {
  841.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  842.     }
  843.   else
  844.     {
  845.       if (parsed == TRUE)
  846.         /* output parsed data */
  847.         {
  848.           printf ("%s\n", id2string(control, pagecontrolfield));
  849.           printf ("Mode Parameter Header:\n");
  850.           printf (" Mode Data Length: %hu\n", scsi_data[0]);
  851.           printf (" Medium Type: %hu\n", scsi_data[1]);
  852.           printf (" Device-Specific Parameter: %hu\n", scsi_data[2]);
  853.           printf (" Block Descriptor Length: %hu\n", scsi_data[3]);
  854.  
  855.       for (i = 0; i < scsi_data[3]; i +=8)    /* print block descriptors */
  856.         {
  857.           printf("Block Descriptor Density Code: %hu\n",scsi_data[(i)+4]);
  858.           printf(" Number of Blocks: %lu\n", (scsi_data[(i)+5]<<16) + (scsi_data[(i)+6]<<8) + (scsi_data[(i)+7]) );
  859.           printf(" Byte 4 (reserved): %hu\n", scsi_data[(i)+8]);
  860.           printf(" Block length: %lu\n", (scsi_data[(i)+9]<<16) + (scsi_data[(i)+10]<<8) + (scsi_data[(i)+11]) );
  861.         }
  862.  
  863.       for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  864.         {
  865.           printf("Page Code: %hu\n",scsi_data[i] & 0x3f);
  866.           printf(" Page can%s be saved\n", (scsi_data[i] & 0x80) ? "" : " not");
  867.           printf(" Page Length: %hu\n", scsi_data[i+1]);
  868.           printf(" Mode Parameters:\n");
  869.           rawhexasciioutput(&scsi_data[i+2], scsi_data[i+1], 2);
  870.         }
  871.         }
  872.       else
  873.         /* output raw data */
  874.         {
  875.           rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  876.         }
  877.     }
  878. }
  879.  
  880. /*********************************************************************
  881.  *
  882.  *    function to read CD-ROM data block address header
  883.  *    starting block and number of blocks.
  884.  */
  885.  
  886. void
  887. read_cdblockheader (BOOLEAN parsed, ULONG block)
  888. {
  889.   static SCSICMD10 command =
  890.   {
  891.     SCSI_CMD_READHEADER,    /* 0x44 READ HEADER scsi command */
  892.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  893.     0, 0, 0, 0,            /* Logical Block Address (ULONG) */
  894.     PAD,            /* reserved */
  895.     0,0,            /* allocated data length */
  896.     PAD                /* control */
  897.   };
  898.  
  899.   static IDTOSTRING udatafieldcont[] =
  900.   {
  901.     0x00, "All bytes zero",
  902.     0x01, "User Data",
  903.     0x02, "User Data",
  904.     -1, "Reserved"
  905.   };
  906.  
  907.   static IDTOSTRING auxfieldcont[] =
  908.   {
  909.     0x00, "All bytes zero",
  910.     0x01, "L-EC symbols",
  911.     0x02, "User Data",
  912.     -1, "Reserved"
  913.   };
  914.  
  915.   int err;
  916.  
  917.   command.b2 = block>>24;
  918.   command.b3 = block>>16;
  919.   command.b4 = block>>8;
  920.   command.b5 = block;
  921. #if MAX_CDDALEN > 65536
  922.   command.b7 = 255;
  923.   command.b8 = 255;
  924. #else
  925.   command.b7 = MAX_CDDALEN>>8;
  926.   command.b8 = MAX_CDDALEN & 0xff;
  927. #endif
  928.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  929.                         (UBYTE *) &command, sizeof (command),
  930.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  931.     {
  932.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  933.     }
  934.   else
  935.     {
  936.       if (parsed == TRUE)
  937.         {
  938.           printf("User Data Field Contents (2048 bytes): %d = %s\n",
  939.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], udatafieldcont));
  940.           printf("Auxiliary Field Contents ( 288 bytes): %d = %s\n",
  941.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], auxfieldcont));
  942.           printf("Byte 1 (reserved): %d\n",(cdda_buf[0])[1]);
  943.           printf("Byte 2 (reserved): %d\n",(cdda_buf[0])[2]);
  944.           printf("Byte 3 (reserved): %d\n",(cdda_buf[0])[3]);
  945.           printf("Absolute CD-ROM Address: %lu\n",
  946.          ((cdda_buf[0])[4] << 24) | ((cdda_buf[0])[5] << 16) | ((cdda_buf[0])[6] << 8) | ((cdda_buf[0])[7]));
  947.         }
  948.       else
  949.         {
  950.           rawhexasciioutput(cdda_buf[0], 8, 0);
  951.         }
  952.     }
  953. }
  954.  
  955. /*********************************************************************
  956.  *
  957.  *    function to read subchannel data audio from Sony CDROM with
  958.  *    starting block and number of blocks.
  959.  */
  960.  
  961. void
  962. read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track)
  963. {
  964.   static SCSICMD10 command =
  965.   {
  966.     SCSI_CMD_READSUBCHANNEL,    /* 0x42 READ SUB-CHANNEL scsi command */
  967.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  968.     0x40,            /* return Sub-Q Channel data */
  969.     0,                /* Sub-channel Data Format */
  970.     PAD,
  971.     PAD,
  972.     0,                /* Track Number 1-99 */
  973.     0,0,            /* allocated data length */
  974.     PAD                /* control */
  975.   };
  976.  
  977.   static IDTOSTRING audiostatus[] =
  978.   {
  979.     0x00, "Audio status byte not supported or not valid",
  980.     0x11, "Audio play operation in progress.",
  981.     0x12, "Audio play operation paused.",
  982.     0x13, "Audio play operation successfully completed.",
  983.     0x14, "Audio play operation stopped due to error.",
  984.     0x15, "No current audio status to return",
  985.     -1, "Reserved, unknown or no audio status"
  986.   };
  987.  
  988.   static IDTOSTRING Qfield[] =
  989.   {
  990.     0x00, "Sub-channel Q mode information not supplied.",
  991.     0x01, "Sub-channel Q encodes current position data.",
  992.     0x02, "Sub-channel Q encodes media catalog number.",
  993.     0x03, "Sub-channel Q encodes ISRC.",
  994.     -1, "Reserved"
  995.   };
  996.  
  997.   int err;
  998.  
  999.   command.b2 = subchannel;
  1000.   command.b3 = subchannelformat;
  1001.   command.b6 = track;
  1002.  
  1003. #if MAX_CDDALEN > 65536
  1004.   command.b7 = 255;
  1005.   command.b8 = 255;
  1006. #else
  1007.   command.b7 = MAX_CDDALEN & 0xff;
  1008.   command.b8 = MAX_CDDALEN>>8;    /* Allocation length = max. data length */
  1009. #endif
  1010.  
  1011.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1012.                         (UBYTE *) &command, sizeof (command),
  1013.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1014.     {
  1015.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1016.     }
  1017.   else
  1018.     {
  1019.       if (parsed == TRUE)
  1020.         /* parsed output */
  1021.         {
  1022.           if (subchannel == 0x40)
  1023.             {
  1024.               if (subchannelformat == 0)
  1025.                 {
  1026.     /* CHANGE - this doesn't work with my Apple CD300!!!!! */
  1027.           rawhexoutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4);
  1028.                 }
  1029.               else if (subchannelformat == 1)
  1030.                 {
  1031.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1032.           printf("Audio status: %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1033.           printf("Sub-Channel Data Length: %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1034.           printf("Sub-Channel Data Format code (should be 0x01!): %d\n",(cdda_buf[0])[4]);
  1035.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f), Qfield));
  1036.  
  1037.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1038.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1039.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1040.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1041.  
  1042.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1043.           printf("Index Number: %d\n", (cdda_buf[0])[7]);
  1044.           printf("Absolute CD-ROM Address: %lu\n", ((cdda_buf[0])[8] << 24) | ((cdda_buf[0])[9] << 16) | ((cdda_buf[0])[10] << 8) | ((cdda_buf[0])[11]));
  1045.           printf("Track Relative CD-ROM Address: %lu\n", ((cdda_buf[0])[12] << 24) | ((cdda_buf[0])[13] << 16) | ((cdda_buf[0])[14] << 8) | ((cdda_buf[0])[15]));
  1046.                 }
  1047.               else if (subchannelformat == 2)
  1048.                 {
  1049.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1050.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1051.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1052.           printf("Sub-Channel Data Format code (should be 0x02!): %d\n",(cdda_buf[0])[4]);
  1053.           printf("Byte 5 (reserved): %02x\n",(cdda_buf[0])[5]);
  1054.           printf("Byte 6 (reserved): %02x\n",(cdda_buf[0])[6]);
  1055.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1056.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1057.           printf("MCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1058.           printf("Media Catalog Number (UPC/Bar Code):\n");
  1059.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1060.                 }
  1061.               else if (subchannelformat == 3)
  1062.                 {
  1063.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1064.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1065.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1066.           printf("Sub-Channel Data Format code (should be 0x03!): %d\n",(cdda_buf[0])[4]);
  1067.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f) ,Qfield));
  1068.  
  1069.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1070.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1071.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1072.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1073.  
  1074.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1075.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1076.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1077.           printf("TCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1078.           printf("Track International-Standard-Recording-Code (ISRC):\n");
  1079.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1080.                 }
  1081.               else
  1082.                 {
  1083.                   rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1084.                 }
  1085.             }
  1086.           else
  1087.             {
  1088.               rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1089.             }
  1090.         }
  1091.       else
  1092.         /* raw output */
  1093.         {
  1094.       rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1095.         }
  1096.     }
  1097.  
  1098. }
  1099.  
  1100. /*********************************************************************
  1101.  *
  1102.  * subroutine used to printout raw hex data bytes
  1103.  *
  1104.  */
  1105. void
  1106. rawhexoutput (UBYTE *p, UWORD numbytes)
  1107. {
  1108.   UWORD i;
  1109.  
  1110.   for (i = 0; i < numbytes; i++)
  1111.     {
  1112.       printf (" %02x", p[i]);
  1113.     }
  1114.   printf ("\n");
  1115. }
  1116.  
  1117. /*********************************************************************
  1118.  *
  1119.  * subroutine used to printout raw hex data bytes with the
  1120.  * corresponding ASCII values and an index
  1121.  *
  1122.  */
  1123. void
  1124. rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
  1125. {
  1126.   UWORD i, j;
  1127.   UBYTE *boff, *aoff;
  1128.   int xxxlen = strlen (" xx");            /* byte */
  1129.  
  1130.   buffer[5+leadspace] = '=';
  1131.  
  1132.   for (i = 0; i < numbytes; i += BYTES_PER_LINE)
  1133.     {
  1134.       memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1135.       boff = &buffer[7+leadspace];
  1136.       aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
  1137.  
  1138.       sprintf (buffer+leadspace, "%04X = ", i);        /* add offset */
  1139.  
  1140.       for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
  1141.         {
  1142.           sprintf (boff, " %02X", *p);
  1143.           *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
  1144.         }
  1145.  
  1146.       buffer[strlen (buffer)] = ' ';
  1147.       *++aoff = '\n';
  1148.       *++aoff = '\0';
  1149.       printf ("%s", buffer);
  1150.     }
  1151. }
  1152.  
  1153. /*********************************************************************
  1154.  *
  1155.  *    function to read digital audio from Sony CDROM with
  1156.  *    starting block and number of blocks.
  1157.  *    This version uses asynchronous reads.
  1158.  *
  1159.  *    outputs LRLRLR pairs of 16 bit digital stereo audio samples,
  1160.  *    2352 bytes per CD-ROM block
  1161.  *
  1162.  *      or (depending on 'whichchannel')
  1163.  *
  1164.  *      8 bit digital audio samples, either the left or right channel
  1165.  */
  1166.  
  1167. void
  1168. read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel, BYTE use16bit)
  1169. {
  1170.   static struct CMD_RDCDDA
  1171.   {
  1172.     UBYTE cmd;            /* READ CD-DA scsi command 0xD8 */
  1173.     UBYTE pad_a;        /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1174.     ULONG lba;            /* logical block address MSB, , ,LSB */
  1175.     ULONG lbn;            /* number of blocks to transfer MSB, , ,LSB */
  1176.     UBYTE subcode;        /* special sub code selector:
  1177.                       * 0: normal 2352
  1178.                  * 1:
  1179.                  * 2:
  1180.                  * 3: 96 bytes */
  1181.     UBYTE cntrl;        /* Control */
  1182.   } command[NDBLBUF];
  1183.  
  1184.   int err, i = 0, j = 0, k = 0;
  1185.   ULONG nblocks = numblocks, xblocks;
  1186.  
  1187.   for (i = 0; i < NDBLBUF; i++)
  1188.     {
  1189.       command[i].cmd = SCSI_CMD_READCDDA;
  1190.       scsi_status[i] = 0;
  1191.     }
  1192.  
  1193.   for (i = 0; ; )
  1194.     {
  1195.       for (; nblocks > 0 && scsi_status[i] == 0; (++i >= NDBLBUF)? i = 0 : i)
  1196.     {
  1197.       command[i].lba = startblock;
  1198.       command[i].lbn = xblocks = (nblocks > NUM_OF_CDDAFRAMES)? NUM_OF_CDDAFRAMES : nblocks;
  1199.  
  1200.       startblock += xblocks;
  1201.       nblocks -= xblocks;
  1202.  
  1203.       scsi_status[i] = 1;
  1204.  
  1205.       SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1206.                (UBYTE *) & command[i], sizeof (command[i]),
  1207.                (SCSIF_READ | SCSIF_AUTOSENSE));
  1208.     }
  1209.       if (nblocks > 0 && scsi_status[i] == 1)
  1210.     {
  1211.       if ((err = WaitScsiCmd (i)) != 0)
  1212.         {
  1213.           fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1214.         }
  1215.       else
  1216.         {
  1217.           if (use16bit == TRUE && whichchannel == 'S')
  1218.         /* output 16 bit stereo samples */
  1219.         {
  1220.           fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1221.         }
  1222.           else if (whichchannel == 'L')
  1223.         /* output left channel */
  1224.         {
  1225.           if (use16bit == FALSE)
  1226.             /* output raw 8 bit left channel */
  1227.             {
  1228.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1229.             {
  1230.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1231.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1232.             }
  1233.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1234.             }
  1235.           else
  1236.             /* output raw 16 bit left channel */
  1237.             {
  1238.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1239.             {
  1240.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1241.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1242.             }
  1243.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1244.             }
  1245.         }
  1246.           else
  1247.         /* output right channel */
  1248.         {
  1249.           if (use16bit == FALSE)
  1250.             /* output raw 8 bit left channel */
  1251.             {
  1252.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1253.             {
  1254.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1255.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1256.             }
  1257.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1258.             }
  1259.           else
  1260.             /* output raw 16 bit left channel */
  1261.             {
  1262.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1263.             {
  1264.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1265.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1266.             }
  1267.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1268.             }
  1269.         }
  1270.         }
  1271.       scsi_status[i] = 0;
  1272.     }
  1273.       else
  1274.     {
  1275.       for (j = 0; j < NDBLBUF; j++)
  1276.         {
  1277.           if (scsi_status[i] == 1)
  1278.         {
  1279.           if ((err = WaitScsiCmd (i)) != 0)
  1280.             {
  1281.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1282.             }
  1283.           else
  1284.             {
  1285.               if (use16bit == TRUE && whichchannel == 'S')
  1286.             /* output 16 bit stereo samples */
  1287.             {
  1288.               fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1289.             }
  1290.               else if (whichchannel == 'L')
  1291.             /* output left channel */
  1292.             {
  1293.               if (use16bit == FALSE)
  1294.                 /* output raw 8 bit left channel */
  1295.                 {
  1296.                   for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1297.                 {
  1298.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1299.                                   ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1300.                 }
  1301.                   fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1302.                 }
  1303.               else
  1304.                 /* output raw 16 bit left channel */
  1305.                 {
  1306.                   for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1307.                 {
  1308.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1309.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1310.                 }
  1311.                   fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1312.                 }
  1313.             }
  1314.               else
  1315.             /* output right channel */
  1316.             {
  1317.               if (use16bit == FALSE)
  1318.                 /* output raw 8 bit left channel */
  1319.                 {
  1320.                   for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1321.                 {
  1322.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1323.                                   ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1324.                 }
  1325.                   fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1326.                 }
  1327.               else
  1328.                 /* output raw 16 bit left channel */
  1329.                 {
  1330.                   for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1331.                 {
  1332.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1333.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1334.                 }
  1335.                   fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1336.                 }
  1337.             }
  1338.             }
  1339.           scsi_status[i] = 0;
  1340.         }
  1341.           (++i >= NDBLBUF)? i = 0 : i;
  1342.         }
  1343.       break;
  1344.     }
  1345.     }
  1346. }
  1347. #ifndef ASYNC
  1348.  
  1349. /*********************************************************************
  1350.  *
  1351.  *    function to read digital audio from Sony CDROM with
  1352.  *    starting block and number of blocks.
  1353.  *
  1354.  *    outputs LRLRLR pairs of 16 bit digital stereo audio samples,
  1355.  *    2352 bytes per CD-ROM block
  1356.  *
  1357.  *      or (depending on 'whichchannel')
  1358.  *
  1359.  *      8 bit digital audio samples, either the left or right channel
  1360.  */
  1361.  
  1362. void
  1363. read_cdda (ULONG startblock, ULONG numblocks, BYTE whichchannel, BYTE use16bit)
  1364. {
  1365.   static struct CMD_RDCDDA
  1366.   {
  1367.     UBYTE cmd;
  1368.     UBYTE pad_a;
  1369.     ULONG lba;
  1370.     ULONG lbn;
  1371.     UBYTE subcode;
  1372.     UBYTE cntrl;
  1373.   } command =
  1374.   {
  1375.     SCSI_CMD_READCDDA,        /* READ CD-DA scsi command 0xD8 */
  1376.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1377.     0,                /* logical block address MSB, , ,LSB */
  1378.     0,                /* number of blocks to transfer MSB, , ,LSB */
  1379.     0,                /* special sub code selector:
  1380.                       * 0: normal 2352
  1381.                  * 1:
  1382.                  * 2:
  1383.                  * 3: 96 bytes */
  1384.     PAD                /* Control */
  1385.   };
  1386.  
  1387.   int err, i, j;
  1388.   ULONG nblocks = numblocks;
  1389.  
  1390. #ifdef HRTEST
  1391.   command.subcode = subcode;
  1392.   memset (cdda_buf, '\0', MAX_CDDALEN);    /* put spaces in buffer */
  1393. #endif
  1394.  
  1395. #ifdef USE8SVX
  1396.   if (write8svx == TRUE)
  1397.     /* write IFF 8SVX header */
  1398.     {
  1399.       fprintf (stdout, "FORM");
  1400.       fprintf (stdout, "");
  1401.     }
  1402. #endif /* USE8SVX */
  1403.  
  1404.   while (nblocks > NUM_OF_CDDAFRAMES)
  1405.     {
  1406.       command.lba = startblock;
  1407.       command.lbn = NUM_OF_CDDAFRAMES;
  1408.  
  1409.       startblock += NUM_OF_CDDAFRAMES;
  1410.       nblocks -= NUM_OF_CDDAFRAMES;
  1411.  
  1412.  
  1413.       if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1414.                 (UBYTE *) & command, sizeof (command),
  1415.                 (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1416.     {
  1417.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1418.     }
  1419.       else
  1420.     {
  1421.       if (use16bit == TRUE && whichchannel == 'S')
  1422.         /* output 16 bit stereo samples */
  1423.         {
  1424.           fwrite (cdda_buf[0], MAX_CDDALEN, 1, stdout);
  1425.         }
  1426.       else if (whichchannel == 'L')
  1427.         /* output left channel */
  1428.         {
  1429.           if (use16bit == FALSE)
  1430.         /* output raw 8 bit left channel */
  1431.         {
  1432.           for (i = 0; i < (MAX_CDDALEN / 4); i++)
  1433.             {
  1434.               (mono_buf[0])[i] = (BYTE) (((cdda_buf[0])[(4 * i)] + ((cdda_buf[0])[(4 * i) + 1] * 256)) / 256);
  1435.             }
  1436.           fwrite (mono_buf[0], (MAX_CDDALEN / 4), 1, stdout);
  1437.         }
  1438.           else
  1439.         /* output raw 16 bit left channel */
  1440.         {
  1441.           for (i = 0, j = 0; i < (MAX_CDDALEN); i += 4)
  1442.             {
  1443.               (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i]);
  1444.               (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 1]);
  1445.             }
  1446.           fwrite (mono_buf[0], (MAX_CDDALEN / 2), 1, stdout);
  1447.         }
  1448.         }
  1449.       else
  1450.         /* output right channel */
  1451.         {
  1452.           if (use16bit == FALSE)
  1453.         /* output raw 8 bit right channel */
  1454.         {
  1455.           for (i = 0; i < (MAX_CDDALEN / 4); i++)
  1456.             {
  1457.               (mono_buf[0])[i] = (BYTE) (((cdda_buf[0])[(4 * i) + 2] + ((cdda_buf[0])[(4 * i) + 3] * 256)) / 256);
  1458.             }
  1459.           fwrite (mono_buf[0], (MAX_CDDALEN / 4), 1, stdout);
  1460.         }
  1461.           else
  1462.         /* output raw 16 bit right channel */
  1463.         {
  1464.           for (i = 0, j = 0; i < (MAX_CDDALEN); i += 4)
  1465.             {
  1466.               (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 2]);
  1467.               (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 3]);
  1468.             }
  1469.           fwrite (mono_buf[0], (MAX_CDDALEN / 2), 1, stdout);
  1470.         }
  1471.         }
  1472.     }
  1473.     }
  1474.  
  1475.   command.lba = startblock;
  1476.   command.lbn = nblocks;
  1477.  
  1478.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1479.             (UBYTE *) & command, sizeof (command),
  1480.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1481.     {
  1482.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1483.     }
  1484.   else
  1485.     {
  1486.       if (use16bit == TRUE && whichchannel == 'S')
  1487.     /* output 16 bit stereo samples */
  1488.     {
  1489. #ifdef HRTEST
  1490.       fprintf(stderr, "scsi_cmd[0].scsi_Actual = %lu\n", scsi_cmd[0].scsi_Actual);
  1491.       fwrite (cdda_buf[0], scsi_cmd[0].scsi_Actual, 1, stdout);
  1492. #else
  1493.  
  1494.       fwrite (cdda_buf[0], nblocks * 2352, 1, stdout);
  1495. #endif
  1496.     }
  1497.       else if (whichchannel == 'L')
  1498.     /* output left channel */
  1499.     {
  1500.       if (use16bit == FALSE)
  1501.         /* output 8 bit left channel */
  1502.         {
  1503.           for (i = 0; i < ((nblocks * 2352) / 4); i++)
  1504.         {
  1505.           (mono_buf[0])[i] = (BYTE) (((cdda_buf[0])[(4 * i)] + ((cdda_buf[0])[(4 * i) + 1] * 256)) / 256);
  1506.         }
  1507.           fwrite (mono_buf[0], ((nblocks * 2352) / 4), 1, stdout);
  1508.         }
  1509.       else
  1510.         /* output raw 16 bit left channel */
  1511.         {
  1512.           for (i = 0, j = 0; i < (nblocks * 2352); i += 4)
  1513.         {
  1514.           (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i]);
  1515.           (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 1]);
  1516.         }
  1517.           fwrite (mono_buf[0], ((nblocks * 2352) / 2), 1, stdout);
  1518.         }
  1519.     }
  1520.       else
  1521.     /* output right channel */
  1522.     {
  1523.       if (use16bit == FALSE)
  1524.         /* output 8 bit right channel */
  1525.         {
  1526.           for (i = 0; i < ((nblocks * 2352) / 4); i++)
  1527.         {
  1528.           (mono_buf[0])[i] = (BYTE) (((cdda_buf[0])[(4 * i) + 2] + ((cdda_buf[0])[(4 * i) + 3] * 256)) / 256);
  1529.         }
  1530.           fwrite (mono_buf[0], ((nblocks * 2352) / 4), 1, stdout);
  1531.         }
  1532.       else
  1533.         /* output raw 16 bit right channel */
  1534.         {
  1535.           for (i = 0, j = 0; i < (nblocks * 2352); i += 4)
  1536.         {
  1537.           (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 2]);
  1538.           (mono_buf[0])[j++] = (BYTE) ((cdda_buf[0])[i + 3]);
  1539.         }
  1540.           fwrite (mono_buf[0], ((nblocks * 2352) / 2), 1, stdout);
  1541.         }
  1542.     }
  1543.     }
  1544. }
  1545. #endif  /* !ASYNC */
  1546.  
  1547. /*********************************************************************
  1548.  *
  1549.  *    function to read sectors from a starting sector #
  1550.  *    - similar adjacent lines are suppressed on printout.
  1551.  *
  1552.  *    - uses trackdisk.device
  1553.  */
  1554.  
  1555. void
  1556. read_sec (void)
  1557.  
  1558. {
  1559.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1560.   UBYTE *pref;
  1561.   UBYTE *p;
  1562.   UWORD j;
  1563.   UWORD k;
  1564.   int err;
  1565.  
  1566.   /*
  1567.    *  keep printing sectors until ^C , or until error
  1568.    */
  1569.   io_ptr[0]->io_Command = CMD_READ;
  1570.   io_ptr[0]->io_Length = TD_SECTOR;
  1571.   io_ptr[0]->io_Data = (APTR) ip_buf;
  1572.   io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* will be updated... */
  1573.  
  1574.  
  1575.   /*
  1576.    *  keep reading sectors : stop on ^C on bad sector #
  1577.    */
  1578.   for (;; ++secno)
  1579.     {
  1580.       UBYTE *ss;
  1581.       UWORD m_sec_offs;
  1582.  
  1583.       if (breakcheck ())    /* ^C ? */
  1584.     break;
  1585.  
  1586.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1587.  
  1588.       DoIO ((struct IORequest *) io_ptr[0]);
  1589.       if ((err = io_ptr[0]->io_Error) == 0)
  1590.     {
  1591.       printf ("\n");
  1592.       /*
  1593.        * scan this sector ...
  1594.         */
  1595.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1596.            m_sec_offs < TD_SECTOR;
  1597.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1598.         {
  1599.           int xxxlen = strlen (" xx");    /* byte */
  1600.  
  1601.           /*
  1602.            * don't print line if same contents as previous
  1603.            */
  1604.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1605.         {
  1606.           if (m_sec_offs > 1)
  1607.             continue;    /* same */
  1608.         }
  1609.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1610.  
  1611.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1612.  
  1613.           /* set up for loop */
  1614.  
  1615.           k = strlen (buffer);
  1616.           ss = buffer + k;
  1617.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1618.           for (p = sec_click_ptr, j = 0;
  1619.            j < BYTES_PER_LINE;
  1620.            ss += xxxlen, ++j, ++k)
  1621.         {
  1622.           UBYTE dd = *p++;
  1623.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1624.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1625.           buffer[k] = que;
  1626.         }
  1627.  
  1628.           buffer[strlen (buffer)] = ' ';
  1629.           buffer[k++] = '\n';
  1630.           buffer[k++] = '\0';
  1631.  
  1632.           printf ("%s", buffer);
  1633.           pref = sec_click_ptr;
  1634.  
  1635.         }
  1636.     }
  1637.       else
  1638.     {
  1639.       /* else DoIO error */
  1640.  
  1641.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1642.            err, secno, secno, sense_errs (0, err));
  1643.  
  1644.       return;
  1645.     }
  1646.     }
  1647. }
  1648.  
  1649. /*********************************************************************
  1650.  *
  1651.  *    function to read sectors from a starting sector #
  1652.  *    - similar adjacent lines are suppressed on printout.
  1653.  *
  1654.  *    - uses scsi device directly
  1655.  */
  1656.  
  1657. void
  1658. read_sec_scsi (void)
  1659. {
  1660.   static struct CMD_XREAD
  1661.   {
  1662.     UBYTE cmd;
  1663.     UBYTE lba[3];
  1664.     UBYTE numb_secs;
  1665.     UBYTE pad;
  1666.   } command =
  1667.   {
  1668.     SCSI_CMD_RD,
  1669.     0, 0, 0,
  1670.     0,
  1671.     PAD
  1672.   };
  1673.  
  1674.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1675.   UBYTE *pref;
  1676.   UBYTE *p;
  1677.   UWORD j;
  1678.   UWORD k;
  1679.   int err;
  1680.  
  1681.   /*
  1682.    *  keep printing sectors until ^C , or until error
  1683.    */
  1684.  
  1685.  
  1686.   /*
  1687.    *  keep reading sectors : stop on ^C on bad sector #
  1688.    */
  1689.   for (;; ++secno)
  1690.     {
  1691.       UBYTE *ss;
  1692.       UWORD m_sec_offs;
  1693.  
  1694.       command.lba[2] = secno;
  1695.       command.lba[1] = secno >> 8;
  1696.       command.lba[0] = (secno >> 8) & 0x1F;
  1697.  
  1698.       command.numb_secs = 1;
  1699.  
  1700.       if (breakcheck ())    /* ^C ? */
  1701.     break;
  1702.  
  1703.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1704.  
  1705.       if ((err = DoScsiCmd ((UBYTE *) ip_buf, 512,
  1706.                 (UBYTE *) & command, sizeof (command),
  1707.                 (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1708.     {
  1709.       printf ("\n");
  1710.       /*
  1711.        * scan this sector ...
  1712.         */
  1713.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1714.            m_sec_offs < TD_SECTOR;
  1715.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1716.         {
  1717.           int xxxlen = strlen (" xx");    /* byte */
  1718.  
  1719.           /*
  1720.            * don't print line if same contents as previous
  1721.            */
  1722.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1723.         {
  1724.           if (m_sec_offs > 1)
  1725.             continue;    /* same */
  1726.         }
  1727.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1728.  
  1729.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1730.  
  1731.           /* set up for loop */
  1732.  
  1733.           k = strlen (buffer);
  1734.           ss = buffer + k;
  1735.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1736.           for (p = sec_click_ptr, j = 0;
  1737.            j < BYTES_PER_LINE;
  1738.            ss += xxxlen, ++j, ++k)
  1739.         {
  1740.           UBYTE dd = *p++;
  1741.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1742.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1743.           buffer[k] = que;
  1744.         }
  1745.  
  1746.           buffer[strlen (buffer)] = ' ';
  1747.           buffer[k++] = '\n';
  1748.           buffer[k++] = '\0';
  1749.  
  1750.           printf ("%s", buffer);
  1751.           pref = sec_click_ptr;
  1752.  
  1753.         }
  1754.     }
  1755.       else
  1756.     {
  1757.       /* else DoIO error */
  1758.  
  1759.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  1760.            secno, secno, sense_errs (0, err));
  1761.       return;
  1762.     }
  1763.     }
  1764. }
  1765.  
  1766. /*********************************************************************
  1767.  *
  1768.  *    function to stop/start motor on SCSI device
  1769.  *    or eject/insert a medium
  1770.  *
  1771.  */
  1772.  
  1773. void
  1774. motor (int motorstatus)
  1775. {
  1776.   static SCSICMD6 command =
  1777.   {
  1778.     SCSI_CMD_SSU,        /* 0x1B SCSI Start / Stop Unit */
  1779.     0,
  1780.     PAD,
  1781.     PAD,
  1782.     0,                /* start/stop eject/insert */
  1783.     PAD,
  1784.   };
  1785.  
  1786.   int err;
  1787.  
  1788.   command.b4 = motorstatus;
  1789.  
  1790.   if ((err = DoScsiCmd (0, 0,
  1791.             (UBYTE *) & command, sizeof (command),
  1792.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1793.     {
  1794.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1795.     }
  1796. }
  1797.  
  1798. /*********************************************************************
  1799.  *
  1800.  *    function to seek to a cylinder
  1801.  *
  1802.  */
  1803.  
  1804. void
  1805. seek (void)
  1806.  
  1807. {
  1808.   static struct CMD_SEEK
  1809.   {
  1810.     UBYTE cmd;
  1811.     UBYTE pad_a;
  1812.     ULONG lba;
  1813.     UBYTE pad[4];
  1814.   } command =
  1815.   {
  1816.     SCSI_CMD_SKX,
  1817.     PAD,
  1818.     0,
  1819.     PAD, PAD, PAD, PAD
  1820.   };
  1821.  
  1822.   int err;
  1823.   /*
  1824.    *    load sector # (log block addr)
  1825.    */
  1826.  
  1827.   command.lba = secno;
  1828.  
  1829.   if ((err = DoScsiCmd (0, 0,
  1830.             (UBYTE *) & command, sizeof (command),
  1831.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1832.     {
  1833.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1834.            err, secno, secno, sense_errs (0, err));
  1835.     }
  1836. }
  1837.  
  1838. /*********************************************************************
  1839.  *
  1840.  *    function to make an inquiry
  1841.  *
  1842.  */
  1843.  
  1844. void
  1845. inquiry (BOOLEAN parsedoutput)
  1846. {
  1847.   static SCSICMD6 command =
  1848.   {
  1849.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  1850.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1851.     PAD,            /* Page Code */
  1852.     PAD,            /* Reserved */
  1853.     0,                /* Allocation length */
  1854.     PAD                /* Control */
  1855.   };
  1856.  
  1857.   int err;
  1858.  
  1859.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  1860.  
  1861.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1862.             (UBYTE *) & command, sizeof (command),
  1863.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1864.     {
  1865.       int rem = scsi_cmd[0].scsi_Actual;
  1866.  
  1867.       if (parsedoutput == FALSE)
  1868.     {
  1869.       rawhexasciioutput (scsi_data, rem, 0);
  1870.     }
  1871.       else
  1872.     /* parsed output */
  1873.     {
  1874.       static IDTOSTRING devicetype[] =
  1875.       {
  1876.         0x00, "Direct-access device (e.g., magnetic disk)",
  1877.         0x01, "Sequential-access device (e.g., magnetic tape)",
  1878.         0x02, "Printer device",
  1879.         0x03, "Processor device",
  1880.         0x04, "Write-once device (e.g., some optical disks)",
  1881.         0x05, "CD-ROM device",
  1882.         0x06, "Scanner device",
  1883.         0x07, "Optical memory device (e.g., some optical disks)",
  1884.         0x08, "Medium Changer device (e.g., jukeboxes)",
  1885.         0x09, "Communications device",
  1886.         0x0A, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  1887.         0x0B, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  1888.         -1, "Reserved, unknown or no device type"
  1889.       };
  1890.  
  1891.       static IDTOSTRING ansiversion[] =
  1892.       {
  1893.         0x00, "The device might or might not comply to an ANSI-approved standard.",
  1894.         0x01, "The device complies to ANSI X3.131-1986 (SCSI-1).",
  1895.         0x02, "The device complies to (SCSI-2).",
  1896.         -1, "Reserved",
  1897.       };
  1898.  
  1899.       static IDTOSTRING responseformat[] =
  1900.       {
  1901.         0x00, "SCSI-1",
  1902.         0x01, "CCS",
  1903.         0x02, "SCSI-2",
  1904.         -1, "Reserved",
  1905.       };
  1906.  
  1907.       printf ("Peripherial qualifier: %ld\n", (scsi_data[0] & 0xE0) >> 5);
  1908.       printf ("Peripherial device type: $%lx, %s\n", (scsi_data[0] & 0x1F), id2string ((scsi_data[0] & 0x1F), devicetype));
  1909.  
  1910.       printf ("Removable medium: %s\n", (scsi_data[1] & 0x80) ? "yes" : "no");
  1911.       printf ("Device type modifier: %lx\n", scsi_data[1] & 0x7F);
  1912.       printf ("ISO Version: %lx\n", (scsi_data[2] & 0xC0) >> 6);
  1913.       printf ("ECMA Version: %lx\n", (scsi_data[2] & 0x38) >> 3);
  1914.  
  1915.       printf ("ANSI-Approved Version: %ld, %s\n", scsi_data[2] & 0x07, id2string ((scsi_data[2] & 0x07), ansiversion));
  1916.  
  1917.       printf ("AENC: %s\n", (scsi_data[3] & 0x80) ? "yes" : "no");
  1918.       printf ("TrmIOP: does%s support TERMINATE I/O PROCESs message\n", (scsi_data[3] & 0x40) ? "" : "n't");
  1919.  
  1920.       printf ("Response data format: $%lx, conforms to %s\n", scsi_data[3] & 0x0F, id2string ((scsi_data[3] & 0x0F), responseformat));
  1921.       printf ("Additional length: $%lx\n", scsi_data[4]);
  1922.       printf ("INQUIRY[5-6] (Reserved): $%lx, $%lx\n", scsi_data[5], scsi_data[6]);
  1923.       printf ("RelAdr: does%s support relative addressing\n", (scsi_data[7] & 0x80) ? "" : "n't");
  1924.       printf ("WBus32: does%s support 32 wide data transfers\n", (scsi_data[7] & 0x40) ? "" : "n't");
  1925.       printf ("WBus16: does%s support 16 wide data transfers\n", (scsi_data[7] & 0x20) ? "" : "n't");
  1926.       printf ("Sync: does%s support synchronous transfers\n", (scsi_data[7] & 0x10) ? "" : "n't");
  1927.       printf ("Linked: does%s support linked commands\n", (scsi_data[7] & 0x08) ? "" : "n't");
  1928.       printf ("CmdQue: does%s support tagged command queueing\n", (scsi_data[7] & 0x02) ? "" : "n't");
  1929.       printf ("SftRe: responds to RESET condition with %s RESET alternative\n", (scsi_data[7] & 0x01) ? "soft" : "hard");
  1930.       printf ("Vendor identification: %.8s\n", &scsi_data[8]);
  1931.       printf ("Product identification: %.16s\n", &scsi_data[16]);
  1932.       printf ("Product revision level: %.4s\n", &scsi_data[32]);
  1933.       printf ("Vendor specific: %.20s\n", &scsi_data[36]);
  1934.       printf ("Reserved: %.35s\n", &scsi_data[56]);
  1935.     }
  1936.     }
  1937.   else
  1938.     /* error */
  1939.     {
  1940.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  1941.     }
  1942. }
  1943.  
  1944. /*********************************************************************
  1945.  *
  1946.  *    function to read disk capacity
  1947.  *
  1948.  */
  1949.  
  1950. void
  1951. read_capacity (BOOLEAN parsed)
  1952. {
  1953.   static struct CMD_READ_CAPACITY
  1954.   {
  1955.     UBYTE cmd;
  1956.     UBYTE pad_a;
  1957.     ULONG lba;
  1958.     UBYTE pad_b[2];
  1959.     UBYTE pmi;
  1960.     UBYTE pad_c;
  1961.   } command =
  1962.   {
  1963.     SCSI_CMD_RCP,    /* READ CAPACITY = READ CD-ROM CAPACITY */
  1964.     PAD,        /* LUN | rsrvd. | RelAddr */
  1965.     0,            /* start from sec 0 */
  1966.     PAD, PAD,
  1967.     0,            /* PMI */
  1968.     PAD
  1969.   };
  1970.  
  1971.   int err;
  1972.  
  1973.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1974.             (UBYTE *) & command, sizeof (command),
  1975.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1976.     {
  1977.       if (parsed == TRUE)
  1978.         /* output parsed data */
  1979.         {
  1980.           ULONG sec_no = *((ULONG *) & scsi_data[0]);
  1981.           ULONG sec_size = *((ULONG *) & scsi_data[4]);
  1982.  
  1983.           printf ("Max Sec = %7ld , sec size = %4ld (capacity = %7ld KB)\n",
  1984.                   sec_no, sec_size, (sec_no * sec_size) / 1024);
  1985.         }
  1986.       else
  1987.         /* output raw data */
  1988.         {
  1989.           rawhexasciioutput (scsi_data, 8, 0);
  1990.         }
  1991.     }
  1992.   else
  1993.     {
  1994.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1995.     }
  1996. }
  1997.  
  1998. /*********************************************************************
  1999.  *
  2000.  *    function to read audio CD TOC (table of contents)
  2001.  *
  2002.  */
  2003.  
  2004. void
  2005. read_toc (int toclong)
  2006. {
  2007.   static IDTOSTRING Qfield[] =
  2008.   {
  2009.     0x00, "Sub-channel Q mode information not supplied.",
  2010.     0x01, "Sub-channel Q encodes current position data.",
  2011.     0x02, "Sub-channel Q encodes media catalog number.",
  2012.     0x03, "Sub-channel Q encodes ISRC.",
  2013.     -1, "Reserved"
  2014.   };
  2015.  
  2016.   static IDTOSTRING Qfieldshort[] =
  2017.   {
  2018.     0x00, "not.suppl.",
  2019.     0x01, "cur.posdt.",
  2020.     0x02, "med.cat.#.",
  2021.     0x03, "ISRC",
  2022.     -1, "reserved"
  2023.   };
  2024.  
  2025.   static SCSICMD10 command =
  2026.   {
  2027.     SCSI_CMD_READTOC,        /* SCSI command read table of contents */
  2028.     0,
  2029.     PAD, PAD, PAD, PAD,
  2030.     0,                /* starting track */
  2031.     0x03, 0x24,            /* max. TOC data length on current CD-ROMs 804 bytes
  2032.                    or 100 TOC track descriptors */
  2033.     PAD
  2034.   };
  2035.  
  2036.   int err, tocsize;
  2037.   UBYTE *tocptr;
  2038.  
  2039.   if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
  2040.             (UBYTE *) & command, sizeof (command),
  2041.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2042.     {
  2043.       tocsize = (toc_buf[0] << 8) | toc_buf[1];        /* first word encodes length */
  2044.  
  2045.       if (toclong == 0)
  2046.         /* display TOC raw form */
  2047.         {
  2048.           rawhexasciioutput(toc_buf, (toc_buf[0]<<8 | toc_buf[1]), 0);
  2049.         }
  2050.       else if (toclong == 1)
  2051.     /* display TOC short form */
  2052.     {
  2053.           printf ("TOC len: %d\n", tocsize);
  2054.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2055.  
  2056.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2057.         tocsize -= 2;
  2058.  
  2059.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2060.         {
  2061.           printf ("#%3.3d: ADR:%10.10s %-15.15s Dig.copy.%5.5s. %-9.9s %cChan. %ld\n",
  2062.               tocptr[2],
  2063.               id2string (((tocptr[1] >> 4) & 0x0F), Qfieldshort),
  2064.               (tocptr[1] & 0x01) ? "pre-emphasis" : "no-pre-emphasis",
  2065.               (tocptr[1] & 0x02) ? "prmtd" : "prohb.",
  2066.               (tocptr[1] & 0x04) ? "Data tr." : "Audio tr.",
  2067.               (tocptr[1] & 0x08) ? '4' : '2',
  2068.               ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]))
  2069.         );
  2070.         }
  2071.     }
  2072.       else if (toclong == 2)
  2073.     /* display TOC long form */
  2074.     {
  2075.           printf ("TOC len: %d\n", tocsize);
  2076.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2077.  
  2078.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2079.         tocsize -= 2;
  2080.  
  2081.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2082.         {
  2083.  
  2084.           printf ("Track number: %d\n", tocptr[2]);
  2085.  
  2086.           printf (" ADR: $%lx: %s\n", ((tocptr[1] >> 4) & 0x0F), id2string (((tocptr[1] >> 4) & 0x0F), Qfield));
  2087.  
  2088.           printf (" Audio with%s pre-emphasis.  ", (tocptr[1] & 0x01) ? "" : "out");
  2089.           printf (" Digital copy %s\n", (tocptr[1] & 0x02) ? "permitted" : "prohibited");
  2090.           printf (" %s track.  ", (tocptr[1] & 0x04) ? "Data" : "Audio");
  2091.           printf (" %s channel audio.  ", (tocptr[1] & 0x08) ? "Four" : "Two");
  2092.  
  2093.           printf (" Absolute address: %ld\n", ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7])));
  2094.         }
  2095.     }
  2096.       else
  2097.     /* toclong is neither 0,1 or 2 - this should never happen! */
  2098.     {
  2099.       fprintf (stderr, "Error : internal error in read_toc!\n");
  2100.     }
  2101.     }
  2102.   else
  2103.     {
  2104.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2105.     }
  2106. }
  2107.  
  2108. /*********************************************************************
  2109.  *
  2110.  *    function to play audio
  2111.  *
  2112.  */
  2113.  
  2114. void
  2115. play_audio (int starttrack, int startindex, int endtrack, int endindex)
  2116. {
  2117.   static SCSICMD10 command =
  2118.   {
  2119.     SCSI_CMD_PLAYAUDIOTRACKINDEX,    /* Play audio track */
  2120.     PAD,            /* LUN */
  2121.     PAD,            /* Reserved */
  2122.     PAD,            /* Reserved */
  2123.     0,                /* Starting Track */
  2124.     0,                /* Starting Index */
  2125.     PAD,            /* Reserved */
  2126.     0,                /* Ending Track */
  2127.     0,                /* Ending Index */
  2128.     PAD                /* Control */
  2129.   };
  2130.  
  2131.   int err;
  2132.  
  2133.   command.b4 = starttrack;    /* set audio track to play */
  2134.   command.b5 = startindex;
  2135.   command.b7 = endtrack;    /* ending track */
  2136.   command.b8 = endindex;
  2137.  
  2138.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2139.             (UBYTE *) & command, sizeof (command),
  2140.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  2141.     {
  2142.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2143.     }
  2144. }
  2145.  
  2146. /*********************************************************************
  2147.  *
  2148.  *    function to compare two binary strings
  2149.  *
  2150.  *    returns FALSE if different
  2151.  */
  2152.  
  2153. int
  2154. gcomp (char *p1, char *p2, int len)
  2155. {
  2156.   while (len--)
  2157.     {
  2158.       if (*p1++ != *p2++)
  2159.     return (FALSE);
  2160.     }
  2161.   return (TRUE);
  2162. }
  2163.  
  2164. /*********************************************************************
  2165.  *
  2166.  * searches DeviceList for a device name with a given string in it.
  2167.  * - if found returns with a pointer to it, else NULL
  2168.  */
  2169.  
  2170. extern struct ExecBase *SysBase;
  2171.  
  2172. UBYTE *
  2173. GetDevName (char *grep)
  2174. {
  2175.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  2176.   NODE *ln;
  2177.  
  2178.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  2179.     {
  2180.       UBYTE *p = ln->ln_Name;
  2181.  
  2182.       while (*p != '.')
  2183.     {
  2184.       if (strncmp (p, grep, 4) == 0)
  2185.         {
  2186.           return (ln->ln_Name);
  2187.         }
  2188.       ++p;
  2189.     }
  2190.     }
  2191.  
  2192.   return (NULL);        /* not found */
  2193. }
  2194.  
  2195. /*********************************************************************
  2196.  *
  2197.  *    Break (^C) function
  2198.  *
  2199.  */
  2200.  
  2201. int
  2202. breakcheck (void)
  2203. {
  2204.   int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  2205.   if (zz)
  2206.     {
  2207.       printf ("\n***BREAK: ^C\n");
  2208.     }
  2209.   return (zz);
  2210. }
  2211.  
  2212. #ifdef __SASC
  2213. /*********************************************************************
  2214.  *
  2215.  *  tell SAS to turn of CTRL-C checking
  2216.  */
  2217. void __regargs
  2218. __chkabort (void)
  2219. {
  2220. }
  2221.  
  2222. #endif
  2223.  
  2224. /*********************************************************************
  2225.  *
  2226.  *    function to send a scsi command (uses asynchronous I/O)
  2227.  *
  2228.  */
  2229. void
  2230. SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2231. {
  2232.  
  2233.   io_ptr[req]->io_Length = sizeof (SCSICMD);
  2234.   io_ptr[req]->io_Data = (APTR) & scsi_cmd[req];
  2235.   io_ptr[req]->io_Command = HD_SCSICMD;
  2236.  
  2237.   scsi_cmd[req].scsi_Data = (APTR) data;
  2238.   scsi_cmd[req].scsi_Length = datasize;
  2239.   scsi_cmd[req].scsi_SenseActual = 0;
  2240.   scsi_cmd[req].scsi_SenseData = scsi_sense[req];
  2241.   scsi_cmd[req].scsi_SenseLength = SENSE_LEN;
  2242.   scsi_cmd[req].scsi_Command = cmd;
  2243.   scsi_cmd[req].scsi_CmdLength = cmdsize;
  2244.   scsi_cmd[req].scsi_Flags = flags;
  2245.  
  2246.   (void) SendIO ((struct IORequest *) io_ptr[req]);
  2247.  
  2248. }
  2249.  
  2250. /*********************************************************************
  2251.  *
  2252.  *    function to wait for an asynchronous scsi command
  2253.  *
  2254.  */
  2255. int
  2256. WaitScsiCmd (int req)
  2257. {
  2258.   int i;
  2259.  
  2260.   WaitIO ((struct IORequest *) io_ptr[req]);
  2261.  
  2262.   if (scsi_cmd[req].scsi_SenseActual)
  2263.     {
  2264.       fprintf (stderr, "SENSE_DATA:");
  2265.       for (i = 0; i < scsi_cmd[req].scsi_SenseActual; i++)
  2266.     {
  2267.       fprintf (stderr, " %02x", scsi_cmd[req].scsi_SenseData[i]);
  2268.     }
  2269.       fprintf (stderr, "\n");
  2270.     }
  2271.   return (io_ptr[req]->io_Error);
  2272. }
  2273.  
  2274. /*********************************************************************
  2275.  *
  2276.  *    function to use a scsi command
  2277.  *
  2278.  */
  2279. int
  2280. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2281. {
  2282.   int i;
  2283.  
  2284.   io_ptr[0]->io_Length = sizeof (SCSICMD);
  2285.   io_ptr[0]->io_Data = (APTR) & scsi_cmd[0];
  2286.   io_ptr[0]->io_Command = HD_SCSICMD;
  2287.  
  2288.   scsi_cmd[0].scsi_Data = (APTR) data;
  2289.   scsi_cmd[0].scsi_Length = datasize;
  2290.   scsi_cmd[0].scsi_SenseActual = 0;
  2291.   scsi_cmd[0].scsi_SenseData = scsi_sense[0];
  2292.   scsi_cmd[0].scsi_SenseLength = SENSE_LEN;
  2293.   scsi_cmd[0].scsi_Command = cmd;
  2294.   scsi_cmd[0].scsi_CmdLength = cmdsize;
  2295.   scsi_cmd[0].scsi_Flags = flags;
  2296.  
  2297.   (void) DoIO ((struct IORequest *) io_ptr[0]);
  2298.  
  2299.   if (scsi_cmd[0].scsi_SenseActual)
  2300.     {
  2301.       fprintf (stderr, "SENSE_DATA:");
  2302.       for (i = 0; i < scsi_cmd[0].scsi_SenseActual; i++)
  2303.     {
  2304.       fprintf (stderr, " %02x", scsi_cmd[0].scsi_SenseData[i]);
  2305.     }
  2306.       fprintf (stderr, "\n");
  2307.     }
  2308.   return (io_ptr[0]->io_Error);
  2309. }
  2310.  
  2311. /*********************************************************************
  2312.  *
  2313.  *    function to return an error string
  2314.  *
  2315.  *
  2316.  */
  2317.  
  2318. UBYTE *
  2319. err_str (int err)
  2320. {
  2321.  
  2322.   static UBYTE *errors[] =
  2323.   {
  2324.     " cannot issue SCSI command to self ",
  2325.     " DMA error ",
  2326.     " illegal or unexpected SCSI phase ",
  2327.     " SCSI parity error ",
  2328.     " Select timed out ",
  2329.     " status and/or sense error "
  2330.   };
  2331.  
  2332.   err -= 40;
  2333.  
  2334.   if ((err < 0) || (err > 5))
  2335.     return ("Error out-of-range");
  2336.   else
  2337.     return (errors[err]);
  2338. }
  2339.  
  2340. /*********************************************************************
  2341.  *
  2342.  *    usage function
  2343.  *
  2344.  *
  2345.  */
  2346.  
  2347. void
  2348. usage (void)
  2349. {
  2350.   static char *zz[] =
  2351.   {
  2352.     "Usage: SCSIutil [-dscsi_dev] <scsi_id> <command>\n",
  2353.     " -c[r]               : Read capacity [raw]\n",
  2354.     " -d<l|r|s> sec blks  : Read 16 bit raw digital audio(start sector/# blocks)(2)\n",
  2355.     " -D<l|r> sec blks    : Read  8 bit raw digital audio(left or right channel)(3)\n",
  2356.     " -e <0|1>            : Change medium (0=eject, 1=load)\n",
  2357.     " -i[r]               : Inquiry [raw]\n",
  2358.     " -h[r] blk           : Read CD-ROM data block address header\n",
  2359.     " -m <0|1>            : Stop/Start motor {0=stop, 1=start}\n",
  2360.     " -o[r] contr page    : Mode sense (contr = 0-3))\n",
  2361.     " -p st si et ei      : Play audio CD track (1-99), index (1-99)\n",
  2362.     " -r[t] sec_no        : Read sectors [use trackdisk.device]\n",
  2363.     " -s sec_no           : Seek to sector (5)\n",
  2364.     " -t[r|l]             : Display TOC of an audio CD [raw|long]\n",
  2365.     " -u[r] chan fmt track: Read CD sub-channel information [raw] (6)\n",
  2366. #ifdef HRTEST
  2367.     " -x<l|r> mod sec blks: Read 16 bit raw digital audio (blk not used)\n",
  2368. #endif
  2369. #ifdef USE8SVX
  2370.     " -8<l|r|s> sec blks : Read digital audio -> 8SVX (left, right or stereo) (5)\n",
  2371. #endif    /* USE8SVX */
  2372.     "\n",
  2373.     "Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
  2374.     "     2: with 's' returns LRLRLR pairs of stereo audio, 2352 bytes per block\n",
  2375.     "     3: converted to 8 bit audio (-d and -D work with Sony CDU 561 & 8003)\n",
  2376.     "     4: contr 0: current, 1: changeable, 2: default, 3: saved values\n",
  2377.     "     5: to park heads, try sec_no of -1\n",
  2378.     "     6: Q-channel = 64, fmt: 0=Sub-Q Channel data,1=current CD-ROM pos.,\n",
  2379.     "        2=Media Catalog Number (UPC/Bar Code),3=Track ISRC\n",
  2380. #ifdef USE8SVX
  2381.     "     7: output 8SVX IFF (in case of stereo needs to read the CD twice)\n",
  2382. #endif    /* USE8SVX */
  2383.     ""                /* TERM */
  2384.   };
  2385.  
  2386.   int j = 0;
  2387.  
  2388.   fprintf (stderr, "SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
  2389.        VERSION, __DATE__, __TIME__, pname);
  2390.   fprintf (stderr, "         additional features by Heiko Rath, hr@brewhr.swb.de\n");
  2391.  
  2392.   while (*zz[j++])
  2393.     fprintf (stderr, "%s", zz[j - 1]);
  2394. }
  2395.  
  2396. /*********************************************************************
  2397.  *
  2398.  *    sense_errs function ; prints sense errors
  2399.  *
  2400.  *
  2401.  */
  2402.  
  2403. UBYTE *
  2404. sense_errs (int req, int err)
  2405. {
  2406.   typedef struct
  2407.   {
  2408.     BYTE code;
  2409.     BYTE sense;
  2410.     UBYTE *ptr;
  2411.   } S_ERRS;
  2412.  
  2413. /*
  2414.  *    only the likely, interesting ones filled in, e.g media errors
  2415.  */
  2416.   static S_ERRS x[] =
  2417.   {
  2418.     0x00, 0x00, "No error",
  2419.     0x01, 0x04, "?",
  2420.     0x02, 0x04, "?",
  2421.     0x03, 0x04, "?",
  2422.     0x04, 0x02, "?",
  2423.     0x06, 0x04, "?",
  2424.     0x09, 0x04, "?",
  2425.     0x10, 0x03, "?",
  2426.     0x10, 0x04, "?",
  2427.     0x11, 0x03, "?",
  2428.     0x12, 0x03, "?",
  2429.     0x13, 0x03, "?",
  2430.     0x14, 0x03, "?",
  2431.     0x15, 0x04, "Seek error ",
  2432.     0x17, 0x01, "?",
  2433.     0x18, 0x01, "?",
  2434.     0x19, 0x03, "?",
  2435.     0x1A, 0x05, "?",
  2436.     0x20, 0x05, "Invalid command op code",
  2437.     0x21, 0x05, "Illegal sector address",
  2438.     0x24, 0x05, "?",
  2439.     0x25, 0x05, "Invalid LUN",
  2440.     0x26, 0x05, "Invalid field in parameter list",
  2441.     0x29, 0x06, "?",
  2442.     0x2A, 0x06, "?",
  2443.     0x31, 0x03, "?",
  2444.     0x32, 0x01, "?",
  2445.     0x32, 0x03, "?",
  2446.     0x40, 0x04, "?",
  2447.     0x41, 0x04, "?",
  2448.     0x42, 0x04, "Power-on diagnostic failure",
  2449.     0x43, 0x04, "?",
  2450.     0x45, 0x04, "Select / reselect failure ",
  2451.     0x47, 0x04, "SCSI Interface Parity Error",
  2452.     0x48, 0x0B, "?",
  2453.     0x49, 0x0B, "Illegal message drive can't support",
  2454.     -1, -1, "ILLEGAL sense!!"
  2455.   };
  2456.  
  2457.   int j = 0;
  2458.   UBYTE *p;
  2459.   char sense;
  2460.   char code;
  2461.  
  2462.   /*
  2463.    *    verify that sense data looks valid
  2464.    */
  2465.   if (((scsi_cmd[req].scsi_Status & 2) == 0) ||
  2466.       (scsi_cmd[req].scsi_SenseActual < OFFS_KEY))
  2467.     {
  2468.       return ("");
  2469.     }
  2470.   sense = scsi_cmd[req].scsi_SenseData[OFFS_KEY] & 0xF;
  2471.   code = scsi_cmd[req].scsi_SenseData[OFFS_CODE];
  2472.  
  2473.   do
  2474.     {
  2475.       p = x[j].ptr;
  2476.       if ((x[j].code == code) && (x[j].sense == sense))
  2477.     break;
  2478.   } while (x[j++].code != -1);
  2479.  
  2480.   return (p);
  2481. }
  2482.  
  2483. /*********************************************************************
  2484.  *
  2485.  *    id2string function ; return pointer to string for matching id
  2486.  *
  2487.  */
  2488.  
  2489. UBYTE *
  2490. id2string (int id, IDTOSTRING * idtable)
  2491. {
  2492.   int j = 0;
  2493.   UBYTE *p;
  2494.  
  2495.   do
  2496.     {
  2497.       p = idtable[j].ptr;
  2498.       if (idtable[j].code == id)
  2499.     break;
  2500.   } while (idtable[j++].code != -1);
  2501.   return p;
  2502. }
  2503.